package com.springboot.demo.valid.config;

import com.sanbi.common.vo.ResponseVo;

import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.springframework.core.annotation.Order;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@ControllerAdvice
@Order
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 处理方法传递非法参数或类型不匹配时异常
     */
    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseBody
    public ResponseVo<Object> badArgumentHandler(IllegalArgumentException e) {
        log.error(e.getMessage(), e);
        return ResponseVo.fail("wrong request param");
    }

    /**
     * 处理WebMvc解析控制器方法参数类型不匹配时异常
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseBody
    public ResponseVo<Object> badArgumentHandler(MethodArgumentTypeMismatchException e) {
        log.error(e.getMessage(), e);
        return ResponseVo.fail("parameter type Error");
    }

    /**
     * 处理必传参数无入参时异常
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    public ResponseVo<Object> badArgumentHandler(MissingServletRequestParameterException e) {
        log.error(e.getMessage(), e);
        return ResponseVo.fail("parameter missing");
    }

    /**
     * 处理json反序列化时异常
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseBody
    public ResponseVo<Object> badArgumentHandler(HttpMessageNotReadableException e) {
        log.error(e.getMessage(), e);
        return ResponseVo.fail("parameter not resolve");
    }

    /**
     * JSR303参数值校验异常
     */
    @ExceptionHandler(ValidationException.class)
    @ResponseBody
    public ResponseVo<Object> badArgumentHandler(ValidationException e) {
        log.error(e.getMessage(), e);
        if (e instanceof ConstraintViolationException) {
            ConstraintViolationException exs = (ConstraintViolationException) e;
            Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
            for (ConstraintViolation<?> item : violations) {
                String message = ((PathImpl) item.getPropertyPath()).getLeafNode().getName() + item.getMessage();
                return ResponseVo.fail(402, message);
            }
        }
        return ResponseVo.fail("bad req argument");
    }

    @ExceptionHandler(BindException.class)
    @ResponseBody
    protected ResponseVo<Object> badArgumentHandler(BindException ex) {
        List<String> errors = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(x -> x.getDefaultMessage())
                .collect(Collectors.toList());
        return ResponseVo.fail(401, errors.get(0));
    }

    /**
     * 入参验证全通过时，则为服务端异常，需后端人员检查项目工程
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseVo<Object> seriousHandler(Exception e) {
        log.error(e.getMessage(), e);
        return ResponseVo.fail("serious error");
    }

}
